#!/usr/bin/env python
# coding=utf-8

"""
xml2json:https://github.com/hay/xml2json
log_debug, print 相当于print
"""
import hashlib
import pprint
from urllib import quote

from flask import current_app, jsonify
from hashlib import md5
import requests, time, json
from xml.etree import ElementTree
from xml2json import xml2json
import optparse
import xmltodict
from web.wechat import HttpClient, WeixinHelper, WxPayConf_pub


class WeiXinPay():
    """微信支付，返回回客户端需要参数
    """
    response = None  # 微信返回的响应
    url = None  # 接口链接
    curl_timeout = None  # curl超时时间

    def __init__(self, out_trade_no, body, total_fee, nonce_str, spbill_create_ip='8.8.8.8',
                 timeout=WxPayConf_pub.CURL_TIMEOUT):
        """
        :param order_id: 订单ID
        :param body: 订单信息
        :param total_fee: 订单金额
        :param nonce_str: 32位内随机字符串
        :param spbill_create_ip: 客户端请求IP地址
        """
        self.params = {
            'appid': current_app.config['OPEN_WECHAT_APPID'],
            'mch_id': current_app.config['MCHID'],
            'nonce_str': nonce_str,
            'body': body,
            'out_trade_no': str(out_trade_no),
            'total_fee': str(int(total_fee)),
            # 'total_fee': str(1),
            'spbill_create_ip': spbill_create_ip,
            'trade_type': 'APP',
            'notify_url': current_app.config['APP_WEIXIN_NOTIFY_URL']
        }

        self.url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'  # 微信请求url
        self.error = None
        self.curl_timeout = timeout

    def key_value_url(self, value):
        """将将键值对转为 key1=value1&key2=value2
        """
        key_az = sorted(value.keys())
        pair_array = []
        for k in key_az:
            v = value.get(k, '').strip()
            v = v.encode('utf8')
            k = k.encode('utf8')
            # print ('%s => %s' % (k, v))
            pair_array.append('%s=%s' % (k, v))

        tmp = '&'.join(pair_array)
        # print ("key_value_url ==> %s " % tmp)
        return tmp

    def arrayToXml(self):
        """array转xml"""
        xml = "<xml>"
        for k, v in self.params.items():
            v = v.encode('utf8')
            k = k.encode('utf8')
            xml += '<' + k + '>' + v + '</' + k + '>'
        xml += "</xml>"
        return "".join(xml)


    def returnXml(self, arr):
        """array转xml"""
        xml = ["<xml>"]
        for k, v in arr.iteritems():
            if v.isdigit():
                xml.append("<{0}>{1}</{0}>".format(k, v))
            else:
                xml.append("<{0}><![CDATA[{1}]]></{0}>".format(k, v))
        xml.append("</xml>")
        return "".join(xml)

    def get_sign(self, params):
        """生成sign
        """
        stringA = self.key_value_url(params)
        stringSignTemp = stringA + '&key=' + current_app.config['APIKEY']  # APIKEY, API密钥，需要在商户后台设置
        # print("stringSignTemp ==> %s" % stringSignTemp)
        sign = (hashlib.md5(stringSignTemp).hexdigest()).upper()
        params['sign'] = sign
        print("sign ==> %s" % sign)

    def getSign(self, params):
        """生成签名"""
        # 签名步骤一：按字典序排序参数,formatBizQueryParaMap已做
        String = self.key_value_url(params)
        # 签名步骤二：在string后加入KEY
        String = "{0}&key={1}".format(String, current_app.config['APIKEY'])
        # 签名步骤三：MD5加密
        String = hashlib.md5(String).hexdigest()
        # 签名步骤四：所有字符转为大写
        sign = String.upper()
        params['sign'] = sign


    def get_req_xml(self):
        """拼接XML
        """
        # self.get_sign(self.params)
        self.get_sign(self.params)
        return self.arrayToXml()

    def postXml(self):
        """post请求xml"""
        xml = self.get_req_xml()
        # print xml
        # xml = """
        # <xml>
        #     <appid>wx2eef37029c7e3eaa</appid>
        #     <body>test</body>
        #     <mch_id>1297854601</mch_id>
        #     <nonce_str>1fhawnq32k3q11fwzoi0cd2fmgvz1wdz</nonce_str>
        #     <notify_url>http://myx.pypyhc.com/shop/api/wechat_payback</notify_url>
        #     <out_trade_no>201603067633389</out_trade_no>
        #     <spbill_create_ip>8.8.8.8</spbill_create_ip>
        #     <total_fee>600</total_fee>
        #     <trade_type>APP</trade_type>
        #     <sign>74274B42091BF6AD6D71C848C916655B</sign>
        # </xml>
        # """
        self.response = self.postXmlCurl(xml, self.url, self.curl_timeout)

        return self.response

    def postXmlCurl(self, xml, url, second=30):
        """以post方式提交xml到对应的接口url"""
        return HttpClient().postXml(xml, url, second=second)

    def xmlToArray(self, xml):
        """将xml转为array"""
        return WeixinHelper.xmlToArray(xml)

    def getPrepayId2(self):
        """获取prepay_id"""
        self.postXml()

        self.result = self.xmlToArray(self.response)
        print "result:", self.result

        xml_status = self.result['return_code']
        return_msg = self.result['return_msg']
        print("result_code ==> %s" % xml_status)
        if xml_status != 'SUCCESS':
            self.error = u"连接微信出错啦！"
            print return_msg
            return {"result": {}, "type": 0, "error": return_msg.encode("utf-8")}
        else:
            prepay_id = self.result["prepay_id"]
            self.params['prepay_id'] = prepay_id
            self.params['package'] = 'Sign=WXPay'
            self.params['timestamp'] = str(int(time.time()))
            return {"result": {}, "type": 1, "error": ""}

    def get_prepay_id(self):
        """
        请求获取prepay_id
        """
        xml = self.get_req_xml()

        headers = {'Content-Type': 'application/xml'}
        # 请求方式1
        r = requests.post(self.url, data=xml, headers=headers)
        print("++++++++++++++++++++++++++")
        re_xml = ElementTree.fromstring(r.text)
        xml_status = re_xml.getiterator('return_code')[0].text
        return_msg = re_xml.getiterator('return_msg')[0].text
        print("result_code ==> %s" % xml_status)
        if xml_status != 'SUCCESS':
            print return_msg
            self.error = u"连接微信出错啦！"
            return {"result": {}, "type": 0, "error": return_msg.encode("utf-8")}
        prepay_id = re_xml.getiterator('prepay_id')[0].text
        self.params['prepay_id'] = prepay_id
        self.params['package'] = 'Sign=WXPay'
        self.params['timestamp'] = str(int(time.time()))
        return {"result": {}, "type": 1, "error": ""}

    def re_finall(self):
        """得到prepay_id后再次签名，返回给终端参数
        """
        if self.error:
            return

        sign_again_params = {
            'appid': self.params['appid'],
            'noncestr': self.params['nonce_str'],
            'package': self.params['package'],
            'partnerid': self.params['mch_id'],
            'timestamp': self.params['timestamp'],
            'prepayid': self.params['prepay_id']
        }
        self.get_sign(sign_again_params)
        self.params['sign'] = sign_again_params['sign']
        self.params['partnerid'] = sign_again_params['partnerid']

        # 移除其他不需要返回参数
        for i in self.params.keys():
            if i not in [
                'appid', 'partnerid', 'nonce_str',
                'timestamp', 'sign', 'package', 'prepay_id']:
                self.params.pop(i)
        print self.params
        return self.params


class WeiXinResponse(WeiXinPay):
    """
    微信签名验证
    """

    def __init__(self, xml):
        """
        :param xml: 支付成功回调的XML
        """
        self.xml = xml
        self.xml_json = dict(dict(xmltodict.parse(self.xml))['xml'])
        print self.xml_json
        self.sign = self.xml_json.get('sign', '')

    def verify(self):
        """验证签名"""

        self.xml_json.pop('sign')
        self.get_sign(self.xml_json)
        if self.sign != self.xml_json['sign']:
            print("signValue:%s !=  sing:%s" % (self.xml_json['sign'], self.sign))
            return False

        return True
